/**
 * Project Name:xiaocao-java-basic
 * File Name:RSACodec.java
 * Package Name:xiaocao.java.basic.encrypt.decrypt
 * Date:2019年4月10日上午8:44:28
 * Copyright (c) 2019, wanzhengchong@163.com All Rights Reserved.
 *
*/

package top.wanzc.java.basic.encrypt.decrypt;
/**
 * ClassName:RSACodec <br/>
 * Function: TODO ADD FUNCTION. <br/>
 * Reason:	 TODO ADD REASON. <br/>
 * Date:     2019年4月10日 上午8:44:28 <br/>
 * @author   zhengchong.wan
 * @version  
 * @since    JDK 1.6
 * @see 	 
 */
import java.security.Key;  
import java.security.KeyFactory;  
import java.security.KeyPair;  
import java.security.KeyPairGenerator;  
import java.security.PrivateKey;  
import java.security.PublicKey;  
import java.security.interfaces.RSAPrivateKey;  
import java.security.interfaces.RSAPublicKey;  
import java.security.spec.PKCS8EncodedKeySpec;  
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.HashMap;  
import java.util.Map;  
  
import javax.crypto.Cipher;  
  
public class RSACodec {  
	
    //非对称密钥算法    
    public static final String KEY_ALGORITHM = "RSA";    
    
    /**  
          * 密钥长度，DH算法的默认密钥长度是1024  
          * 密钥长度必须是64的倍数，在512到65536位之间  
     * 
     */ 
    private static final int KEY_SIZE = 512;    
    
    // 公钥    
    private static final String PUBLIC_KEY = "xiaoxiaorenzhe";    
        
    // 私钥    
    private static final String PRIVATE_KEY = "dadapangzi";    
      
    /**  
          * 初始化密钥对  
     * @return Map 甲方密钥的Map  
     * */    
    public static Map<String,Object> initKey() throws Exception{    
        // 实例化密钥生成器    
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM);    
        //初始化密钥生成器    
        keyPairGenerator.initialize(KEY_SIZE);    
        //生成密钥对    
        KeyPair keyPair = keyPairGenerator.generateKeyPair();   
        //甲方公钥    
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();    
        System.out.println("系数：" + publicKey.getModulus() + "  加密指数：" + publicKey.getPublicExponent());  
        //甲方私钥    
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();   
        System.out.println("系数：" + privateKey.getModulus() + "解密指数：" + privateKey.getPrivateExponent());  
        //将密钥存储在map中    
        Map<String,Object> keyMap = new HashMap<String,Object>();    
        keyMap.put(PUBLIC_KEY, publicKey);    
        keyMap.put(PRIVATE_KEY, privateKey);    
        return keyMap;    
    }    
      
    /**  
          * 私钥加密  
     * @param data待加密数据  
     * @param key 密钥  
     * @return byte[] 加密数据  
     * */    
    public static byte[] encryptByPrivateKey(byte[] data, byte[] key) throws Exception{    
        //取得私钥    
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(key);    
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);    
        //生成私钥    
        PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);    
        //数据加密    
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());    
        cipher.init(Cipher.ENCRYPT_MODE, privateKey);    
        return cipher.doFinal(data);    
    }    
      
    /**  
          *  公钥加密  
     * @param data待加密数据  
     * @param key 密钥  
     * @return byte[] 加密数据  
     * */    
    public static byte[] encryptByPublicKey(byte[] data,byte[] key) throws Exception{    
            
        //实例化密钥工厂    
        KeyFactory keyFactory=KeyFactory.getInstance(KEY_ALGORITHM);    
        //初始化公钥    
        //密钥材料转换    
        X509EncodedKeySpec x509KeySpec=new X509EncodedKeySpec(key);    
        //产生公钥    
        PublicKey pubKey=keyFactory.generatePublic(x509KeySpec);    
            
        //数据加密    
        Cipher cipher=Cipher.getInstance(keyFactory.getAlgorithm());    
        cipher.init(Cipher.ENCRYPT_MODE, pubKey);    
        return cipher.doFinal(data);    
    }  
    
    /**  
          * 私钥解密  
     * @param data 待解密数据  
     * @param key 密钥  
     * @return byte[] 解密数据  
     * */    
    public static byte[] decryptByPrivateKey(byte[] data,byte[] key) throws Exception{    
        //取得私钥    
        PKCS8EncodedKeySpec pkcs8KeySpec=new PKCS8EncodedKeySpec(key);    
        KeyFactory keyFactory=KeyFactory.getInstance(KEY_ALGORITHM);    
        //生成私钥    
        PrivateKey privateKey=keyFactory.generatePrivate(pkcs8KeySpec);    
        //数据解密    
        Cipher cipher=Cipher.getInstance(keyFactory.getAlgorithm());    
        cipher.init(Cipher.DECRYPT_MODE, privateKey);    
        return cipher.doFinal(data);    
    }    
      
    /**  
          * 公钥解密  
     * @param data 待解密数据  
     * @param key 密钥  
     * @return byte[] 解密数据  
     * */    
    public static byte[] decryptByPublicKey(byte[] data,byte[] key) throws Exception{    
            
        //实例化密钥工厂    
        KeyFactory keyFactory=KeyFactory.getInstance(KEY_ALGORITHM);    
        //初始化公钥    
        //密钥材料转换    
        X509EncodedKeySpec x509KeySpec=new X509EncodedKeySpec(key);    
        //产生公钥    
        PublicKey pubKey=keyFactory.generatePublic(x509KeySpec);    
        //数据解密    
        Cipher cipher=Cipher.getInstance(keyFactory.getAlgorithm());    
        cipher.init(Cipher.DECRYPT_MODE, pubKey);    
        return cipher.doFinal(data);    
    }    
      
    /**  
          * 取得私钥  
     * @param keyMap 密钥map  
     * @return byte[] 私钥  
     * */    
    public static byte[] getPrivateKey(Map<String,Object> keyMap){    
        Key key=(Key)keyMap.get(PRIVATE_KEY);    
        return key.getEncoded();    
    }    
    /**  
          * 取得公钥  
     * @param keyMap 密钥map  
     * @return byte[] 公钥  
     * */    
    public static byte[] getPublicKey(Map<String,Object> keyMap) throws Exception{    
        Key key=(Key) keyMap.get(PUBLIC_KEY);   
        return key.getEncoded();    
    }    
     
    public static void main(String[] args) throws Exception {    
        //初始化密钥    
        //生成密钥对    
        Map<String,Object> keyMap = RSACodec.initKey();    
        //公钥    
        byte[] publicKey = RSACodec.getPublicKey(keyMap);  
        //byte[] publicKey = b;  
        //私钥    
        byte[] privateKey = RSACodec.getPrivateKey(keyMap);    
        System.out.println("公钥：" + Base64.getEncoder().encode(publicKey));         
        System.out.println("私钥：" + Base64.getEncoder().encode(privateKey));    
            
        System.out.println("================密钥对构造完毕,甲方将公钥公布给乙方，开始进行加密数据的传输=============");    
        String str="aattaggcctegthththfef/aat.mp4";    
        System.out.println("===========甲方向乙方发送加密数据==============");    
        System.out.println("原文:" + str);    
        //甲方进行数据的加密    
        byte[] code1 = RSACodec.encryptByPublicKey(str.getBytes(), publicKey);  
        System.out.println("甲方 使用乙方公钥加密后的数据：" + Base64.getEncoder().encode(code1));    
        System.out.println("===========乙方使用甲方提供的公钥对数据进行解密==============");    
        //乙方进行数据的解密    
        //byte[] decode1=RSACoder.decryptByPublicKey(code1, publicKey);    
        byte[] decode1 = RSACodec.decryptByPrivateKey(code1, privateKey);    
        System.out.println("乙方解密后的数据："+new String(decode1)+"");    
            
        System.out.println("===========反向进行操作，乙方向甲方发送数据==============");    
            
        str="乙方向甲方发送数据RSA算法";    
            
        System.out.println("原文:"+str);    
            
        //乙方使用公钥对数据进行加密    
        byte[] code2 = RSACodec.encryptByPublicKey(str.getBytes(), publicKey);    
        System.out.println("===========乙方使用公钥对数据进行加密==============");    
        System.out.println("加密后的数据："+Base64.getEncoder().encode(code2));    
            
        System.out.println("=============乙方将数据传送给甲方======================");    
        System.out.println("===========甲方使用私钥对数据进行解密==============");    
            
        //甲方使用私钥对数据进行解密    
        byte[] decode2 = RSACodec.decryptByPrivateKey(code2, privateKey);    
            
        System.out.println("甲方解密后的数据："+new String(decode2));   
        
        // 私钥做电子签名
        byte[] encryptByPrivateKeyData = RSACodec.encryptByPrivateKey("private key sign, public key auth".getBytes(), privateKey);
        // 公钥做认证
        byte[] decryptByPublicKeyData = RSACodec.decryptByPublicKey(encryptByPrivateKeyData, publicKey);
        System.out.println(new String(decryptByPublicKeyData));
    }    
}  

